[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Definition of the interpreter state and entry point.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
|
|
|
|
#define LLVM_CLANG_AST_INTERP_INTERP_H
|
|
|
|
|
2023-01-21 19:32:02 +01:00
|
|
|
#include "Boolean.h"
|
2023-01-25 14:51:16 +01:00
|
|
|
#include "Floating.h"
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
#include "Function.h"
|
2023-01-11 12:12:52 +01:00
|
|
|
#include "FunctionPointer.h"
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
#include "InterpFrame.h"
|
|
|
|
#include "InterpStack.h"
|
|
|
|
#include "InterpState.h"
|
|
|
|
#include "Opcode.h"
|
|
|
|
#include "PrimType.h"
|
|
|
|
#include "Program.h"
|
|
|
|
#include "State.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/ASTDiagnostic.h"
|
|
|
|
#include "clang/AST/CXXInheritance.h"
|
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
#include "llvm/ADT/APSInt.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
#include <limits>
|
|
|
|
#include <type_traits>
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace interp {
|
|
|
|
|
|
|
|
using APInt = llvm::APInt;
|
|
|
|
using APSInt = llvm::APSInt;
|
|
|
|
|
2021-08-31 12:31:24 +05:30
|
|
|
/// Convert a value to an APValue.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <typename T> bool ReturnValue(const T &V, APValue &R) {
|
|
|
|
R = V.toAPValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks if the variable has externally defined storage.
|
|
|
|
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if the array is offsetable.
|
|
|
|
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
2021-08-31 12:31:24 +05:30
|
|
|
/// Checks if a pointer is live and accessible.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
|
|
|
/// Checks if a pointer is null.
|
|
|
|
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
CheckSubobjectKind CSK);
|
|
|
|
|
|
|
|
/// Checks if a pointer is in range.
|
|
|
|
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
|
|
|
|
|
|
|
/// Checks if a field from which a pointer is going to be derived is valid.
|
|
|
|
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
CheckSubobjectKind CSK);
|
|
|
|
|
|
|
|
/// Checks if a pointer points to const storage.
|
|
|
|
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a pointer points to a mutable field.
|
|
|
|
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a value can be loaded from a block.
|
|
|
|
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
/// Checks if a value can be stored in a block.
|
|
|
|
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a method can be invoked on an object.
|
|
|
|
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a value can be initialized.
|
|
|
|
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a method can be called.
|
2022-10-28 10:31:47 +02:00
|
|
|
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
2023-04-17 15:23:37 +02:00
|
|
|
/// Checks if calling the currently active function would exceed
|
|
|
|
/// the allowed call depth.
|
|
|
|
bool CheckCallDepth(InterpState &S, CodePtr OpPC);
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
/// Checks the 'this' pointer.
|
|
|
|
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
|
|
|
|
|
|
|
|
/// Checks if a method is pure virtual.
|
|
|
|
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
|
|
|
|
|
2022-10-25 17:34:31 +02:00
|
|
|
/// Checks that all fields are initialized after a constructor call.
|
|
|
|
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
|
|
|
|
|
2023-05-19 11:12:05 +02:00
|
|
|
/// Checks if reinterpret casts are legal in the current context.
|
|
|
|
bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
|
|
|
|
const Pointer &Ptr);
|
|
|
|
|
2023-01-19 13:24:40 +01:00
|
|
|
/// Checks if the shift operation is legal.
|
2023-05-09 19:38:37 +02:00
|
|
|
template <typename LT, typename RT>
|
|
|
|
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
|
|
|
|
unsigned Bits) {
|
2023-01-19 13:24:40 +01:00
|
|
|
if (RHS.isNegative()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
|
|
|
|
// the shifted type.
|
|
|
|
if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
const APSInt Val = RHS.toAPSInt();
|
|
|
|
QualType Ty = E->getType();
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-09 19:38:37 +02:00
|
|
|
|
|
|
|
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
|
|
|
|
// operand, and must not overflow the corresponding unsigned type.
|
|
|
|
if (LHS.isNegative())
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
|
|
|
|
else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_lshift_discards);
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++2a [expr.shift]p2: [P0907R4]:
|
|
|
|
// E1 << E2 is the unique value congruent to
|
|
|
|
// E1 x 2^E2 module 2^N.
|
2023-01-19 13:24:40 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
/// Checks if Div/Rem operation on LHS and RHS is valid.
|
|
|
|
template <typename T>
|
2023-01-19 12:37:20 +01:00
|
|
|
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
|
|
|
|
if (RHS.isZero()) {
|
2023-08-09 14:27:46 +02:00
|
|
|
const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
|
|
|
|
S.FFDiag(Op, diag::note_expr_divide_by_zero)
|
|
|
|
<< Op->getRHS()->getSourceRange();
|
2023-01-19 12:37:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
|
|
|
|
APSInt LHSInt = LHS.toAPSInt();
|
|
|
|
SmallString<32> Trunc;
|
|
|
|
(-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2022-10-07 10:38:33 +02:00
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
/// Checks if the result is a floating-point operation is valid
|
|
|
|
/// in the current context.
|
|
|
|
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
|
|
|
|
|
2022-10-07 15:49:37 +02:00
|
|
|
/// Interpreter entry point.
|
|
|
|
bool Interpret(InterpState &S, APValue &Result);
|
|
|
|
|
2023-01-07 12:05:05 +01:00
|
|
|
/// Interpret a builtin function.
|
2023-07-18 07:47:20 +02:00
|
|
|
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
|
|
|
const CallExpr *Call);
|
2022-11-05 13:08:40 +01:00
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
enum class ArithOp { Add, Sub };
|
|
|
|
|
2023-01-07 12:05:05 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Returning values
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2023-07-28 21:01:05 +02:00
|
|
|
/// Pop arguments of builtins defined as func-name(...).
|
|
|
|
bool popBuiltinArgs(InterpState &S, CodePtr OpPC);
|
|
|
|
|
2023-05-11 12:01:17 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
2023-01-07 12:05:05 +01:00
|
|
|
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
const T &Ret = S.Stk.pop<T>();
|
|
|
|
|
2023-07-09 20:09:59 +02:00
|
|
|
// Make sure returned pointers are live. We might be trying to return a
|
|
|
|
// pointer or reference to a local variable.
|
|
|
|
// Just return false, since a diagnostic has already been emitted in Sema.
|
|
|
|
if constexpr (std::is_same_v<T, Pointer>) {
|
|
|
|
// FIXME: We could be calling isLive() here, but the emitted diagnostics
|
|
|
|
// seem a little weird, at least if the returned expression is of
|
|
|
|
// pointer type.
|
|
|
|
if (!Ret.isLive())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-08-24 11:36:23 -07:00
|
|
|
assert(S.Current);
|
2023-01-07 12:05:05 +01:00
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
2023-07-28 21:01:05 +02:00
|
|
|
if (!S.checkingPotentialConstantExpression() || S.Current->Caller) {
|
|
|
|
// Certain builtin functions are declared as func-name(...), so the
|
|
|
|
// parameters are checked in Sema and only available through the CallExpr.
|
|
|
|
// The interp::Function we create for them has 0 parameters, so we need to
|
|
|
|
// remove them from the stack by checking the CallExpr.
|
2023-08-24 11:36:23 -07:00
|
|
|
if (S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()))
|
2023-07-28 21:01:05 +02:00
|
|
|
popBuiltinArgs(S, PC);
|
|
|
|
else
|
|
|
|
S.Current->popArgs();
|
|
|
|
}
|
2023-01-07 12:05:05 +01:00
|
|
|
|
|
|
|
if (InterpFrame *Caller = S.Current->Caller) {
|
|
|
|
PC = S.Current->getRetPC();
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = Caller;
|
|
|
|
S.Stk.push<T>(Ret);
|
|
|
|
} else {
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = nullptr;
|
|
|
|
if (!ReturnValue<T>(Ret, Result))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
2023-05-11 12:01:17 +02:00
|
|
|
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
|
2023-01-07 12:05:05 +01:00
|
|
|
S.Current->popArgs();
|
|
|
|
|
|
|
|
if (InterpFrame *Caller = S.Current->Caller) {
|
|
|
|
PC = S.Current->getRetPC();
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = Caller;
|
|
|
|
} else {
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = nullptr;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Add, Sub, Mul
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <typename T, bool (*OpFW)(T, T, unsigned, T *),
|
|
|
|
template <typename U> class OpAP>
|
|
|
|
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
|
|
|
|
const T &RHS) {
|
|
|
|
// Fast path - add the numbers with fixed width.
|
|
|
|
T Result;
|
|
|
|
if (!OpFW(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If for some reason evaluation continues, use the truncated results.
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
|
|
|
|
// Slow path - compute the result using another bit of precision.
|
|
|
|
APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
|
|
|
|
|
|
|
|
// Report undefined behaviour, stopping if required.
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
2021-06-09 11:06:23 +01:00
|
|
|
SmallString<32> Trunc;
|
|
|
|
Value.trunc(Result.bitWidth()).toString(Trunc, 10);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Add(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() + 1;
|
|
|
|
return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::add(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Sub(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() + 1;
|
|
|
|
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::sub(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Mul(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::mul(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
2022-09-30 16:59:50 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS & RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitAnd(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-06 15:13:11 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS | RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitOr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitOr(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-22 16:59:19 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS ^ RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitXor(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitXor(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:40:55 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Rem(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
2022-09-27 17:40:55 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
T Result;
|
|
|
|
if (!T::rem(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 18:17:52 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS / RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Div(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
2022-09-27 18:17:52 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
T Result;
|
|
|
|
if (!T::div(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::div(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2022-08-09 08:08:48 +02:00
|
|
|
// Inv
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Inv(InterpState &S, CodePtr OpPC) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const T &Val = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = Val.bitWidth();
|
|
|
|
Boolean R;
|
|
|
|
Boolean::inv(BoolT::from(Val, Bits), &R);
|
|
|
|
|
|
|
|
S.Stk.push<BoolT>(R);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Neg
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Neg(InterpState &S, CodePtr OpPC) {
|
2023-04-22 14:09:14 +02:00
|
|
|
const T &Value = S.Stk.pop<T>();
|
2022-08-09 08:08:48 +02:00
|
|
|
T Result;
|
|
|
|
|
2023-04-22 14:09:14 +02:00
|
|
|
if (!T::neg(Value, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(isIntegralType(Name) &&
|
|
|
|
"don't expect other types to fail at constexpr negation");
|
2022-08-09 08:08:48 +02:00
|
|
|
S.Stk.push<T>(Result);
|
2023-04-22 14:09:14 +02:00
|
|
|
|
|
|
|
APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
|
|
|
SmallString<32> Trunc;
|
|
|
|
NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
|
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
2023-04-22 14:09:14 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
2022-08-09 08:08:48 +02:00
|
|
|
}
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
enum class PushVal : bool {
|
|
|
|
No,
|
|
|
|
Yes,
|
|
|
|
};
|
|
|
|
enum class IncDecOp {
|
|
|
|
Inc,
|
|
|
|
Dec,
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, IncDecOp Op, PushVal DoPush>
|
|
|
|
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
|
|
|
|
T Value = Ptr.deref<T>();
|
|
|
|
T Result;
|
|
|
|
|
|
|
|
if constexpr (DoPush == PushVal::Yes)
|
2023-04-21 09:52:43 +02:00
|
|
|
S.Stk.push<T>(Value);
|
2022-10-21 09:10:29 +02:00
|
|
|
|
|
|
|
if constexpr (Op == IncDecOp::Inc) {
|
|
|
|
if (!T::increment(Value, &Result)) {
|
|
|
|
Ptr.deref<T>() = Result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!T::decrement(Value, &Result)) {
|
|
|
|
Ptr.deref<T>() = Result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Something went wrong with the previous operation. Compute the
|
|
|
|
// result with another bit of precision.
|
|
|
|
unsigned Bits = Value.bitWidth() + 1;
|
|
|
|
APSInt APResult;
|
|
|
|
if constexpr (Op == IncDecOp::Inc)
|
|
|
|
APResult = ++Value.toAPSInt(Bits);
|
|
|
|
else
|
|
|
|
APResult = --Value.toAPSInt(Bits);
|
|
|
|
|
|
|
|
// Report undefined behaviour, stopping if required.
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
|
|
|
SmallString<32> Trunc;
|
|
|
|
APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
|
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
2022-10-21 09:10:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value increased by one back to the pointer
|
|
|
|
/// 4) Pushes the original (pre-inc) value on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Inc(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
|
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value increased by one back to the pointer
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool IncPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
|
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value decreased by one back to the pointer
|
|
|
|
/// 4) Pushes the original (pre-dec) value on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Dec(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
|
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value decreased by one back to the pointer
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool DecPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
|
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
template <IncDecOp Op, PushVal DoPush>
|
|
|
|
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
llvm::RoundingMode RM) {
|
|
|
|
Floating Value = Ptr.deref<Floating>();
|
|
|
|
Floating Result;
|
|
|
|
|
|
|
|
if constexpr (DoPush == PushVal::Yes)
|
|
|
|
S.Stk.push<Floating>(Value);
|
|
|
|
|
|
|
|
llvm::APFloat::opStatus Status;
|
|
|
|
if constexpr (Op == IncDecOp::Inc)
|
|
|
|
Status = Floating::increment(Value, RM, &Result);
|
|
|
|
else
|
|
|
|
Status = Floating::decrement(Value, RM, &Result);
|
|
|
|
|
|
|
|
Ptr.deref<Floating>() = Result;
|
|
|
|
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2023-05-04 15:31:24 +02:00
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
|
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2023-05-04 15:31:24 +02:00
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
|
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2023-05-04 15:31:24 +02:00
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
|
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2023-05-04 15:31:24 +02:00
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
|
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
2022-09-28 14:30:44 +02:00
|
|
|
/// 1) Pops the value from the stack.
|
|
|
|
/// 2) Pushes the bitwise complemented value on the stack (~V).
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Comp(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Val = S.Stk.pop<T>();
|
|
|
|
T Result;
|
|
|
|
if (!T::comp(Val, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-09 08:08:48 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
// EQ, NE, GT, GE, LT, LE
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
return CmpHelper<T>(S, OpPC, Fn);
|
|
|
|
}
|
|
|
|
|
2023-04-25 15:46:20 +02:00
|
|
|
/// Function pointers cannot be compared in an ordered way.
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
|
|
|
|
CompareFn Fn) {
|
|
|
|
const auto &RHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
const auto &LHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx())
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
|
|
|
|
CompareFn Fn) {
|
|
|
|
const auto &RHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
const auto &LHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <>
|
|
|
|
inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!Pointer::hasSameBase(LHS, RHS)) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
2023-04-25 19:53:40 +02:00
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx())
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
unsigned VL = LHS.getByteOffset();
|
|
|
|
unsigned VR = RHS.getByteOffset();
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
|
2019-12-16 17:40:03 -08:00
|
|
|
if (LHS.isZero() && RHS.isZero()) {
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Pointer::hasSameBase(LHS, RHS)) {
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
unsigned VL = LHS.getByteOffset();
|
|
|
|
unsigned VR = RHS.getByteOffset();
|
2022-10-13 10:09:36 +02:00
|
|
|
|
|
|
|
// In our Pointer class, a pointer to an array and a pointer to the first
|
|
|
|
// element in the same array are NOT equal. They have the same Base value,
|
|
|
|
// but a different Offset. This is a pretty rare case, so we fix this here
|
|
|
|
// by comparing pointers to the first elements.
|
|
|
|
if (LHS.inArray() && LHS.isRoot())
|
|
|
|
VL = LHS.atIndex(0).getByteOffset();
|
|
|
|
if (RHS.inArray() && RHS.isRoot())
|
|
|
|
VR = RHS.atIndex(0).getByteOffset();
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool EQ(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool NE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R != ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LT(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Less;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Less ||
|
|
|
|
R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GT(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Greater;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Greater ||
|
|
|
|
R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// InRange
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InRange(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T RHS = S.Stk.pop<T>();
|
|
|
|
const T LHS = S.Stk.pop<T>();
|
|
|
|
const T Value = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
S.Stk.push<bool>(LHS <= Value && Value <= RHS);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Dup, Pop, Test
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Dup(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.push<T>(S.Stk.peek<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Pop(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.pop<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Const
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
|
|
|
|
S.Stk.push<T>(Arg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Get/Set Local/Param/Global/This
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
2022-12-26 09:29:04 +01:00
|
|
|
const Pointer &Ptr = S.Current->getLocalPointer(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-30 16:02:46 +02:00
|
|
|
/// 1) Pops the value from the stack.
|
|
|
|
/// 2) Writes the value to the local variable with the
|
|
|
|
/// given offset.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->setLocal<T>(I, S.Stk.pop<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S.Stk.push<T>(S.Current->getParam<T>(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->setParam<T>(I, S.Stk.pop<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 09:22:34 +02:00
|
|
|
/// 1) Peeks a pointer on the stack
|
|
|
|
/// 2) Pushes the value of the pointer's field on the stack
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const Pointer &Obj = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Obj = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckStore(S, OpPC, Field))
|
|
|
|
return false;
|
2023-03-14 11:08:16 +01:00
|
|
|
Field.initialize();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Field.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 09:22:34 +02:00
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Pushes the value of the pointer's field on the stack
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const Pointer &Obj = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
if (!CheckStore(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
Field.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
auto *B = S.P.getGlobal(I);
|
|
|
|
if (B->isExtern())
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(B->deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
// TODO: emit warning.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 14:40:23 +02:00
|
|
|
/// 1) Converts the value on top of the stack to an APValue
|
|
|
|
/// 2) Sets that APValue on \Temp
|
|
|
|
/// 3) Initialized global with index \I with that
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
|
|
|
|
const LifetimeExtendedTemporaryDecl *Temp) {
|
|
|
|
assert(Temp);
|
|
|
|
const T Value = S.Stk.peek<T>();
|
|
|
|
APValue APV = Value.toAPValue();
|
|
|
|
APValue *Cached = Temp->getOrCreateValue(true);
|
|
|
|
*Cached = APV;
|
|
|
|
|
|
|
|
S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:36:37 +01:00
|
|
|
/// 1) Converts the value on top of the stack to an APValue
|
|
|
|
/// 2) Sets that APValue on \Temp
|
|
|
|
/// 3) Initialized global with index \I with that
|
|
|
|
inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
|
|
|
|
const LifetimeExtendedTemporaryDecl *Temp) {
|
|
|
|
assert(Temp);
|
|
|
|
const Pointer &P = S.Stk.peek<Pointer>();
|
|
|
|
APValue *Cached = Temp->getOrCreateValue(true);
|
|
|
|
|
|
|
|
*Cached = P.toRValue(S.getCtx());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
Field.deref<T>() = S.Stk.pop<T>();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(F->Offset);
|
|
|
|
const auto &Value = S.Stk.pop<T>();
|
|
|
|
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
Field.deref<T>() = S.Stk.pop<T>();
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-16 19:11:58 +02:00
|
|
|
/// 1) Pops the value from the stack
|
2022-10-21 15:43:42 +02:00
|
|
|
/// 2) Peeks a pointer from the stack
|
2022-09-23 11:29:33 +02:00
|
|
|
/// 3) Pushes the value to field I of the pointer on the stack
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
2022-10-21 15:43:42 +02:00
|
|
|
const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Field.deref<T>() = Value;
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
2023-08-10 09:16:10 +02:00
|
|
|
const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &Field = Ptr.atField(I);
|
|
|
|
Field.deref<T>() = Value;
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GetPtr Local/Param/Global/Field/This
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S.Stk.push<Pointer>(S.Current->getParamPointer(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-23 11:29:33 +02:00
|
|
|
/// 1) Pops a Pointer from the stack
|
|
|
|
/// 2) Pushes Pointer.atField(Off) on the stack
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckExtern(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(Ptr.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(This.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
Pointer Field = Ptr.atField(Off);
|
|
|
|
Ptr.deactivate();
|
|
|
|
Field.activate();
|
|
|
|
S.Stk.push<Pointer>(std::move(Field));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
Pointer Field = This.atField(Off);
|
|
|
|
This.deactivate();
|
|
|
|
Field.activate();
|
|
|
|
S.Stk.push<Pointer>(std::move(Field));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
2023-01-05 12:55:29 +01:00
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(Ptr.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(Ptr.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(This.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
|
|
|
|
const Pointer &Ptr) {
|
|
|
|
Pointer Base = Ptr;
|
|
|
|
while (Base.isBaseClass())
|
|
|
|
Base = Base.getBase();
|
|
|
|
|
|
|
|
auto *Field = Base.getRecord()->getVirtualBase(Decl);
|
|
|
|
S.Stk.push<Pointer>(Base.atField(Field->Offset));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
|
|
|
return VirtBaseHelper(S, OpPC, D, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
|
|
|
|
const RecordDecl *D) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Load, Store, Init
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Load(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LoadPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Store(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2022-12-26 09:29:04 +01:00
|
|
|
if (!Ptr.isRoot())
|
|
|
|
Ptr.initialize();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StorePop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2022-12-26 09:29:04 +01:00
|
|
|
if (!Ptr.isRoot())
|
|
|
|
Ptr.initialize();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StoreBitField(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2022-12-26 09:29:04 +01:00
|
|
|
if (!Ptr.isRoot())
|
|
|
|
Ptr.initialize();
|
2023-08-10 09:16:10 +02:00
|
|
|
if (auto *FD = Ptr.getField()) {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
2023-08-10 09:16:10 +02:00
|
|
|
} else {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value;
|
2023-08-10 09:16:10 +02:00
|
|
|
}
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2022-12-26 09:29:04 +01:00
|
|
|
if (!Ptr.isRoot())
|
|
|
|
Ptr.initialize();
|
2023-08-10 09:16:10 +02:00
|
|
|
if (auto *FD = Ptr.getField()) {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
2023-08-10 09:16:10 +02:00
|
|
|
} else {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
Ptr.deref<T>() = Value;
|
2023-08-10 09:16:10 +02:00
|
|
|
}
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-31 16:09:40 +02:00
|
|
|
/// 1) Pops the value from the stack
|
|
|
|
/// 2) Peeks a pointer and gets its index \Idx
|
|
|
|
/// 3) Sets the value on the pointer, leaving the pointer on the stack.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
|
|
|
|
if (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-31 16:09:40 +02:00
|
|
|
/// The same as InitElem, but pops the pointer as well.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
|
|
|
|
if (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// AddOffset, SubOffset
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-12-31 16:44:41 +01:00
|
|
|
template <class T, ArithOp Op>
|
|
|
|
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
|
|
|
|
const Pointer &Ptr) {
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
|
|
|
|
return false;
|
|
|
|
|
2022-10-13 10:09:36 +02:00
|
|
|
// A zero offset does not change the pointer.
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
if (Offset.isZero()) {
|
2022-10-13 10:09:36 +02:00
|
|
|
S.Stk.push<Pointer>(Ptr);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-10-13 10:09:36 +02:00
|
|
|
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
|
|
|
|
return false;
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
// Arrays of unknown bounds cannot have pointers into them.
|
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
2022-10-13 10:09:36 +02:00
|
|
|
// Get a version of the index comparable to the type.
|
|
|
|
T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
// Compute the largest index into the array.
|
|
|
|
unsigned MaxIndex = Ptr.getNumElems();
|
|
|
|
|
|
|
|
// Helper to report an invalid offset, computed as APSInt.
|
|
|
|
auto InvalidOffset = [&]() {
|
|
|
|
const unsigned Bits = Offset.bitWidth();
|
|
|
|
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
|
|
|
|
APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
|
2022-12-31 16:44:41 +01:00
|
|
|
APSInt NewIndex =
|
|
|
|
(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
|
|
|
|
<< NewIndex
|
|
|
|
<< /*array*/ static_cast<int>(!Ptr.inArray())
|
|
|
|
<< static_cast<unsigned>(MaxIndex);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned MaxOffset = MaxIndex - Ptr.getIndex();
|
2022-12-31 16:44:41 +01:00
|
|
|
if constexpr (Op == ArithOp::Add) {
|
2022-09-11 14:39:52 +02:00
|
|
|
// If the new offset would be negative, bail out.
|
|
|
|
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
|
|
|
|
return InvalidOffset();
|
|
|
|
|
|
|
|
// If the new offset would be out of bounds, bail out.
|
|
|
|
if (Offset.isPositive() && Offset > MaxOffset)
|
|
|
|
return InvalidOffset();
|
|
|
|
} else {
|
|
|
|
// If the new offset would be negative, bail out.
|
|
|
|
if (Offset.isPositive() && Index < Offset)
|
|
|
|
return InvalidOffset();
|
|
|
|
|
|
|
|
// If the new offset would be out of bounds, bail out.
|
|
|
|
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
|
|
|
|
return InvalidOffset();
|
|
|
|
}
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
// Offset is valid - compute it on unsigned.
|
|
|
|
int64_t WideIndex = static_cast<int64_t>(Index);
|
|
|
|
int64_t WideOffset = static_cast<int64_t>(Offset);
|
2022-11-09 12:48:43 +01:00
|
|
|
int64_t Result;
|
2022-12-31 16:44:41 +01:00
|
|
|
if constexpr (Op == ArithOp::Add)
|
2022-11-09 12:48:43 +01:00
|
|
|
Result = WideIndex + WideOffset;
|
|
|
|
else
|
|
|
|
Result = WideIndex - WideOffset;
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool AddOffset(InterpState &S, CodePtr OpPC) {
|
2022-12-31 16:44:41 +01:00
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SubOffset(InterpState &S, CodePtr OpPC) {
|
2022-12-31 16:44:41 +01:00
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
template <ArithOp Op>
|
|
|
|
static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC) {
|
|
|
|
using OneT = Integral<8, false>;
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
// Get the current value on the stack.
|
|
|
|
S.Stk.push<Pointer>(Ptr.deref<Pointer>());
|
|
|
|
|
|
|
|
// Now the current Ptr again and a constant 1.
|
2022-12-31 16:44:41 +01:00
|
|
|
Pointer P = Ptr.deref<Pointer>();
|
|
|
|
OneT One = OneT::from(1);
|
|
|
|
if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
|
2022-11-02 09:09:23 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Store the new value.
|
|
|
|
Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
return IncDecPtrHelper<ArithOp::Add>(S, OpPC);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
return IncDecPtrHelper<ArithOp::Sub>(S, OpPC);
|
|
|
|
}
|
|
|
|
|
2022-10-13 10:09:36 +02:00
|
|
|
/// 1) Pops a Pointer from the stack.
|
|
|
|
/// 2) Pops another Pointer from the stack.
|
|
|
|
/// 3) Pushes the different of the indices of the two pointers on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool SubPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!Pointer::hasSameArray(LHS, RHS)) {
|
|
|
|
// TODO: Diagnose.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
T A = T::from(LHS.getIndex());
|
|
|
|
T B = T::from(RHS.getIndex());
|
|
|
|
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
|
|
|
|
}
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Destroy
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->destroy(I);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Cast, CastFP
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
|
|
|
|
using T = typename PrimConv<TIn>::T;
|
|
|
|
using U = typename PrimConv<TOut>::T;
|
|
|
|
S.Stk.push<U>(U::from(S.Stk.pop<T>()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
/// 1) Pops a Floating from the stack.
|
|
|
|
/// 2) Pushes a new floating on the stack that uses the given semantics.
|
2023-07-03 12:43:20 +02:00
|
|
|
inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
|
|
|
|
llvm::RoundingMode RM) {
|
|
|
|
Floating F = S.Stk.pop<Floating>();
|
|
|
|
Floating Result = F.toSemantics(Sem, RM);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-25 14:51:16 +01:00
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
|
|
|
|
const llvm::fltSemantics *Sem,
|
|
|
|
llvm::RoundingMode RM) {
|
|
|
|
const T &From = S.Stk.pop<T>();
|
|
|
|
APSInt FromAP = From.toAPSInt();
|
|
|
|
Floating Result;
|
|
|
|
|
|
|
|
auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Floating &F = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<T, Boolean>) {
|
|
|
|
S.Stk.push<T>(T(F.isNonZero()));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
APSInt Result(std::max(8u, T::bitWidth() + 1),
|
|
|
|
/*IsUnsigned=*/!T::isSigned());
|
|
|
|
auto Status = F.convertToInteger(Result);
|
|
|
|
|
|
|
|
// Float-to-Integral overflow check.
|
|
|
|
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Stk.push<T>(T(Result));
|
|
|
|
return CheckFloatResult(S, OpPC, Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-19 11:12:05 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Zero, Nullptr
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Zero(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.push<T>(T::zero());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool Null(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.push<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// This, ImplicitThis
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool This(InterpState &S, CodePtr OpPC) {
|
|
|
|
// Cannot read 'this' in this mode.
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
S.Stk.push<Pointer>(This);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-04 07:43:34 +01:00
|
|
|
inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
assert(S.Current->getFunction()->hasRVO());
|
2022-12-28 09:34:47 +01:00
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
2022-11-04 07:43:34 +01:00
|
|
|
S.Stk.push<Pointer>(S.Current->getRVOPtr());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Shr, Shl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-10-22 18:19:10 +02:00
|
|
|
template <PrimType NameL, PrimType NameR>
|
|
|
|
inline bool Shr(InterpState &S, CodePtr OpPC) {
|
|
|
|
using LT = typename PrimConv<NameL>::T;
|
|
|
|
using RT = typename PrimConv<NameR>::T;
|
|
|
|
const auto &RHS = S.Stk.pop<RT>();
|
|
|
|
const auto &LHS = S.Stk.pop<LT>();
|
|
|
|
const unsigned Bits = LHS.bitWidth();
|
|
|
|
|
2023-05-09 19:38:37 +02:00
|
|
|
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
|
Revert "[clang][Interp][NFC] Remove shift error checking code duplication"
This reverts commit fddf6418e8492a544c9bfdb42a4dbc949d9dc2ee.
Apparently this also breaks some builders:
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1f54): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<16u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<16u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1fd4): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x2058): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
(etc)
2023-01-19 13:03:20 +01:00
|
|
|
return false;
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
2023-01-26 07:50:14 +01:00
|
|
|
Integral<LT::bitWidth(), false> R;
|
|
|
|
Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
|
|
|
|
S.Stk.push<LT>(R);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-22 18:19:10 +02:00
|
|
|
template <PrimType NameL, PrimType NameR>
|
|
|
|
inline bool Shl(InterpState &S, CodePtr OpPC) {
|
|
|
|
using LT = typename PrimConv<NameL>::T;
|
|
|
|
using RT = typename PrimConv<NameR>::T;
|
|
|
|
const auto &RHS = S.Stk.pop<RT>();
|
|
|
|
const auto &LHS = S.Stk.pop<LT>();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
const unsigned Bits = LHS.bitWidth();
|
|
|
|
|
2023-05-09 19:38:37 +02:00
|
|
|
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
|
Revert "[clang][Interp][NFC] Remove shift error checking code duplication"
This reverts commit fddf6418e8492a544c9bfdb42a4dbc949d9dc2ee.
Apparently this also breaks some builders:
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1f54): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<16u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<16u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1fd4): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x2058): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
(etc)
2023-01-19 13:03:20 +01:00
|
|
|
return false;
|
2022-10-22 18:19:10 +02:00
|
|
|
|
2023-01-26 07:50:14 +01:00
|
|
|
Integral<LT::bitWidth(), false> R;
|
|
|
|
Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
|
|
|
|
S.Stk.push<LT>(R);
|
2022-10-22 18:19:10 +02:00
|
|
|
return true;
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// NoRet
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool NoRet(InterpState &S, CodePtr OpPC) {
|
|
|
|
SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
|
|
|
|
S.FFDiag(EndLoc, diag::note_constexpr_no_return);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// NarrowPtr, ExpandPtr
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
S.Stk.push<Pointer>(Ptr.narrow());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
S.Stk.push<Pointer>(Ptr.expand());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-12-31 17:06:52 +01:00
|
|
|
// 1) Pops an integral value from the stack
|
|
|
|
// 2) Peeks a pointer
|
|
|
|
// 3) Pushes a new pointer that's a narrowed array
|
|
|
|
// element of the peeked pointer with the value
|
|
|
|
// from 1) added as offset.
|
|
|
|
//
|
|
|
|
// This leaves the original pointer on the stack and pushes a new one
|
|
|
|
// with the offset applied and narrowed.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return NarrowPtr(S, OpPC);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return NarrowPtr(S, OpPC);
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) {
|
2022-12-28 11:43:26 +01:00
|
|
|
const Pointer &Obj = S.Stk.peek<Pointer>();
|
2023-02-03 12:20:15 +01:00
|
|
|
return CheckCtorCall(S, OpPC, Obj);
|
2022-12-28 11:43:26 +01:00
|
|
|
}
|
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
|
2022-10-07 15:49:37 +02:00
|
|
|
if (Func->hasThisPointer()) {
|
2023-01-26 14:07:46 +01:00
|
|
|
size_t ThisOffset =
|
|
|
|
Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
|
2023-02-03 12:20:15 +01:00
|
|
|
|
2023-01-26 14:07:46 +01:00
|
|
|
const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
|
|
|
|
|
2023-05-08 15:36:56 +02:00
|
|
|
// If the current function is a lambda static invoker and
|
|
|
|
// the function we're about to call is a lambda call operator,
|
|
|
|
// skip the CheckInvoke, since the ThisPtr is a null pointer
|
|
|
|
// anyway.
|
|
|
|
if (!(S.Current->getFunction() &&
|
|
|
|
S.Current->getFunction()->isLambdaStaticInvoker() &&
|
|
|
|
Func->isLambdaCallOperator())) {
|
|
|
|
if (!CheckInvoke(S, OpPC, ThisPtr))
|
|
|
|
return false;
|
|
|
|
}
|
2022-12-28 09:34:47 +01:00
|
|
|
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
2022-10-07 15:49:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
2022-10-28 10:31:47 +02:00
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
if (!CheckCallable(S, OpPC, Func))
|
2022-10-28 10:31:47 +02:00
|
|
|
return false;
|
2022-10-07 15:49:37 +02:00
|
|
|
|
2023-04-17 15:23:37 +02:00
|
|
|
if (!CheckCallDepth(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
|
2022-10-07 15:49:37 +02:00
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
|
|
|
APValue CallResult;
|
|
|
|
// Note that we cannot assert(CallResult.hasValue()) here since
|
|
|
|
// Ret() above only sets the APValue if the curent frame doesn't
|
|
|
|
// have a caller set.
|
|
|
|
if (Interpret(S, CallResult)) {
|
|
|
|
NewFrame.release(); // Frame was delete'd already.
|
|
|
|
assert(S.Current == FrameBefore);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interpreting the function failed somehow. Reset to
|
|
|
|
// previous state.
|
|
|
|
S.Current = FrameBefore;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-26 16:25:52 +01:00
|
|
|
inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
|
|
|
|
assert(Func->hasThisPointer());
|
|
|
|
assert(Func->isVirtual());
|
|
|
|
size_t ThisOffset =
|
|
|
|
Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
|
|
|
|
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
|
|
|
|
|
|
|
|
const CXXRecordDecl *DynamicDecl =
|
|
|
|
ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
|
|
|
|
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
|
|
|
|
const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
|
|
|
|
const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
|
|
|
|
DynamicDecl, StaticDecl, InitialFunction);
|
|
|
|
|
|
|
|
if (Overrider != InitialFunction) {
|
|
|
|
Func = S.P.getFunction(Overrider);
|
|
|
|
|
|
|
|
const CXXRecordDecl *ThisFieldDecl =
|
|
|
|
ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
|
|
|
|
if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
|
|
|
|
// If the function we call is further DOWN the hierarchy than the
|
|
|
|
// FieldDesc of our pointer, just get the DeclDesc instead, which
|
|
|
|
// is the furthest we might go up in the hierarchy.
|
|
|
|
ThisPtr = ThisPtr.getDeclPtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Call(S, OpPC, Func);
|
|
|
|
}
|
|
|
|
|
2023-07-18 07:47:20 +02:00
|
|
|
inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
|
|
|
|
const CallExpr *CE) {
|
2022-11-05 13:08:40 +01:00
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
|
|
|
|
|
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
2023-07-18 07:47:20 +02:00
|
|
|
if (InterpretBuiltin(S, PC, Func, CE)) {
|
2022-11-05 13:08:40 +01:00
|
|
|
NewFrame.release();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
S.Current = FrameBefore;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
inline bool CallPtr(InterpState &S, CodePtr OpPC) {
|
2023-01-11 12:12:52 +01:00
|
|
|
const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
|
|
|
|
|
|
|
|
const Function *F = FuncPtr.getFunction();
|
|
|
|
if (!F || !F->isConstexpr())
|
|
|
|
return false;
|
|
|
|
|
2023-02-16 08:37:03 +01:00
|
|
|
if (F->isVirtual())
|
|
|
|
return CallVirt(S, OpPC, F);
|
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
return Call(S, OpPC, F);
|
2023-01-11 12:12:52 +01:00
|
|
|
}
|
|
|
|
|
2023-05-11 14:44:39 +02:00
|
|
|
inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
|
2023-01-11 12:12:52 +01:00
|
|
|
assert(Func);
|
|
|
|
S.Stk.push<FunctionPointer>(Func);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-11 16:01:54 +02:00
|
|
|
/// Just emit a diagnostic. The expression that caused emission of this
|
|
|
|
/// op is not valid in a constant context.
|
|
|
|
inline bool Invalid(InterpState &S, CodePtr OpPC) {
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
2023-05-12 09:20:33 +02:00
|
|
|
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
|
|
|
|
<< S.Current->getRange(OpPC);
|
2023-05-11 16:01:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-06-19 16:24:52 +02:00
|
|
|
/// Same here, but only for casts.
|
|
|
|
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
|
2023-08-08 12:22:31 -04:00
|
|
|
<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
|
2023-06-19 16:24:52 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Read opcode arguments
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-09-17 16:14:37 +02:00
|
|
|
template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
|
|
|
|
if constexpr (std::is_pointer<T>::value) {
|
|
|
|
uint32_t ID = OpPC.read<uint32_t>();
|
|
|
|
return reinterpret_cast<T>(S.P.getNativePointer(ID));
|
|
|
|
} else {
|
|
|
|
return OpPC.read<T>();
|
|
|
|
}
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 11:17:56 +02:00
|
|
|
template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
|
|
|
|
Floating F = Floating::deserialize(*OpPC);
|
|
|
|
OpPC += align(F.bytesToSerialize());
|
|
|
|
return F;
|
|
|
|
}
|
|
|
|
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
} // namespace interp
|
|
|
|
} // namespace clang
|
|
|
|
|
|
|
|
#endif
|