[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);
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
|
|
|
/// 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-01-19 13:24:40 +01:00
|
|
|
/// Checks if the shift operation is legal.
|
|
|
|
template <typename RT>
|
|
|
|
bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_expr_divide_by_zero);
|
|
|
|
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.
|
|
|
|
bool InterpretBuiltin(InterpState &S, CodePtr &PC, unsigned BuiltinID);
|
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
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, bool Builtin = false,
|
|
|
|
class T = typename PrimConv<Name>::T>
|
|
|
|
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
S.CallStackDepth--;
|
|
|
|
const T &Ret = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
|
|
|
if (Builtin || !S.checkingPotentialConstantExpression())
|
|
|
|
S.Current->popArgs();
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <bool Builtin = false>
|
|
|
|
inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
S.CallStackDepth--;
|
|
|
|
|
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
|
|
|
if (Builtin || !S.checkingPotentialConstantExpression())
|
|
|
|
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();
|
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
|
|
|
|
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) {
|
|
|
|
const T &Val = S.Stk.pop<T>();
|
|
|
|
T Result;
|
|
|
|
T::neg(Val, &Result);
|
|
|
|
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
|
|
|
|
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();
|
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
|
|
|
|
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) {
|
|
|
|
// FIXME: Check initialization of Ptr
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
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) {
|
|
|
|
// FIXME: Check initialization of Ptr
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
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) {
|
|
|
|
// FIXME: Check initialization of Ptr
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
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) {
|
|
|
|
// FIXME: Check initialization of Ptr
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
[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>();
|
|
|
|
const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
|
|
|
|
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();
|
[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 (auto *FD = Ptr.getField()) {
|
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
|
|
|
} else {
|
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
}
|
|
|
|
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();
|
[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 (auto *FD = Ptr.getField()) {
|
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
|
|
|
} else {
|
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
/// Not templated, so implemented in Interp.cpp.
|
|
|
|
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
|
|
|
|
llvm::RoundingMode RM);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[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-01-19 13:24:40 +01:00
|
|
|
if (!CheckShift<RT>(S, OpPC, 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-01-19 13:24:40 +01:00
|
|
|
if (!CheckShift<RT>(S, OpPC, 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-02-03 12:20:15 +01:00
|
|
|
if (!CheckInvoke(S, OpPC, ThisPtr))
|
2022-12-28 09:34:47 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
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-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;
|
|
|
|
}
|
|
|
|
|
2022-11-05 13:08:40 +01:00
|
|
|
inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func) {
|
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
|
|
|
|
|
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
|
|
|
if (InterpretBuiltin(S, PC, Func->getBuiltinID())) {
|
|
|
|
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-03 12:20:15 +01:00
|
|
|
return Call(S, OpPC, F);
|
2023-01-11 12:12:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetFnPtr(InterpState &S, CodePtr &PC, const Function *Func) {
|
|
|
|
assert(Func);
|
|
|
|
S.Stk.push<FunctionPointer>(Func);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
}
|
|
|
|
|
[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
|