Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Integral.h
213799 views
//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the VM types and helpers operating on types.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H13#define LLVM_CLANG_AST_INTERP_INTEGRAL_H1415#include "clang/AST/APValue.h"16#include "clang/AST/ComparisonCategories.h"17#include "llvm/ADT/APSInt.h"18#include "llvm/Support/MathExtras.h"19#include "llvm/Support/raw_ostream.h"20#include <cstddef>21#include <cstdint>2223#include "Primitives.h"2425namespace clang {26namespace interp {2728using APInt = llvm::APInt;29using APSInt = llvm::APSInt;3031template <bool Signed> class IntegralAP;3233// Helper structure to select the representation.34template <unsigned Bits, bool Signed> struct Repr;35template <> struct Repr<8, false> {36using Type = uint8_t;37};38template <> struct Repr<16, false> {39using Type = uint16_t;40};41template <> struct Repr<32, false> {42using Type = uint32_t;43};44template <> struct Repr<64, false> {45using Type = uint64_t;46};47template <> struct Repr<8, true> {48using Type = int8_t;49};50template <> struct Repr<16, true> {51using Type = int16_t;52};53template <> struct Repr<32, true> {54using Type = int32_t;55};56template <> struct Repr<64, true> {57using Type = int64_t;58};5960/// Wrapper around numeric types.61///62/// These wrappers are required to shared an interface between APSint and63/// builtin primitive numeral types, while optimising for storage and64/// allowing methods operating on primitive type to compile to fast code.65template <unsigned Bits, bool Signed> class Integral final {66private:67template <unsigned OtherBits, bool OtherSigned> friend class Integral;6869// The primitive representing the integral.70using ReprT = typename Repr<Bits, Signed>::Type;71ReprT V;72static_assert(std::is_trivially_copyable_v<ReprT>);7374/// Primitive representing limits.75static const auto Min = std::numeric_limits<ReprT>::min();76static const auto Max = std::numeric_limits<ReprT>::max();7778/// Construct an integral from anything that is convertible to storage.79template <typename T> explicit Integral(T V) : V(V) {}8081public:82using AsUnsigned = Integral<Bits, false>;8384/// Zero-initializes an integral.85Integral() : V(0) {}8687/// Constructs an integral from another integral.88template <unsigned SrcBits, bool SrcSign>89explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}9091/// Construct an integral from a value based on signedness.92explicit Integral(const APSInt &V)93: V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}9495bool operator<(Integral RHS) const { return V < RHS.V; }96bool operator>(Integral RHS) const { return V > RHS.V; }97bool operator<=(Integral RHS) const { return V <= RHS.V; }98bool operator>=(Integral RHS) const { return V >= RHS.V; }99bool operator==(Integral RHS) const { return V == RHS.V; }100bool operator!=(Integral RHS) const { return V != RHS.V; }101bool operator>=(unsigned RHS) const {102return static_cast<unsigned>(V) >= RHS;103}104105bool operator>(unsigned RHS) const {106return V >= 0 && static_cast<unsigned>(V) > RHS;107}108109Integral operator-() const { return Integral(-V); }110Integral operator-(const Integral &Other) const {111return Integral(V - Other.V);112}113Integral operator~() const { return Integral(~V); }114115template <unsigned DstBits, bool DstSign>116explicit operator Integral<DstBits, DstSign>() const {117return Integral<DstBits, DstSign>(V);118}119120template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>121explicit operator Ty() const {122return V;123}124125APSInt toAPSInt() const {126return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);127}128APSInt toAPSInt(unsigned BitWidth) const {129return APSInt(toAPInt(BitWidth), !Signed);130}131APInt toAPInt(unsigned BitWidth) const {132if constexpr (Signed)133return APInt(Bits, static_cast<uint64_t>(V), Signed)134.sextOrTrunc(BitWidth);135else136return APInt(Bits, static_cast<uint64_t>(V), Signed)137.zextOrTrunc(BitWidth);138}139APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }140141Integral<Bits, false> toUnsigned() const {142return Integral<Bits, false>(*this);143}144145constexpr static unsigned bitWidth() { return Bits; }146147bool isZero() const { return !V; }148149bool isMin() const { return *this == min(bitWidth()); }150151bool isMinusOne() const { return Signed && V == ReprT(-1); }152153constexpr static bool isSigned() { return Signed; }154155bool isNegative() const { return V < ReprT(0); }156bool isPositive() const { return !isNegative(); }157158ComparisonCategoryResult compare(const Integral &RHS) const {159return Compare(V, RHS.V);160}161162void bitcastToMemory(std::byte *Dest) const {163std::memcpy(Dest, &V, sizeof(V));164}165166static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {167assert(BitWidth == sizeof(ReprT) * 8);168ReprT V;169170std::memcpy(&V, Src, sizeof(ReprT));171return Integral(V);172}173174std::string toDiagnosticString(const ASTContext &Ctx) const {175std::string NameStr;176llvm::raw_string_ostream OS(NameStr);177OS << V;178return NameStr;179}180181unsigned countLeadingZeros() const {182if constexpr (!Signed)183return llvm::countl_zero<ReprT>(V);184if (isPositive())185return llvm::countl_zero<typename AsUnsigned::ReprT>(186static_cast<typename AsUnsigned::ReprT>(V));187llvm_unreachable("Don't call countLeadingZeros() on negative values.");188}189190Integral truncate(unsigned TruncBits) const {191assert(TruncBits >= 1);192if (TruncBits >= Bits)193return *this;194const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;195const ReprT SignBit = ReprT(1) << (TruncBits - 1);196const ReprT ExtMask = ~BitMask;197return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));198}199200void print(llvm::raw_ostream &OS) const { OS << V; }201202static Integral min(unsigned NumBits) { return Integral(Min); }203static Integral max(unsigned NumBits) { return Integral(Max); }204205template <typename ValT> static Integral from(ValT Value) {206if constexpr (std::is_integral<ValT>::value)207return Integral(Value);208else209return Integral::from(static_cast<Integral::ReprT>(Value));210}211212template <unsigned SrcBits, bool SrcSign>213static std::enable_if_t<SrcBits != 0, Integral>214from(Integral<SrcBits, SrcSign> Value) {215return Integral(Value.V);216}217218static Integral zero(unsigned BitWidth = 0) { return from(0); }219220template <typename T> static Integral from(T Value, unsigned NumBits) {221return Integral(Value);222}223224static bool inRange(int64_t Value, unsigned NumBits) {225return CheckRange<ReprT, Min, Max>(Value);226}227228static bool increment(Integral A, Integral *R) {229return add(A, Integral(ReprT(1)), A.bitWidth(), R);230}231232static bool decrement(Integral A, Integral *R) {233return sub(A, Integral(ReprT(1)), A.bitWidth(), R);234}235236static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {237return CheckAddUB(A.V, B.V, R->V);238}239240static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {241return CheckSubUB(A.V, B.V, R->V);242}243244static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {245return CheckMulUB(A.V, B.V, R->V);246}247248static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {249*R = Integral(A.V % B.V);250return false;251}252253static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {254*R = Integral(A.V / B.V);255return false;256}257258static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {259*R = Integral(A.V & B.V);260return false;261}262263static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {264*R = Integral(A.V | B.V);265return false;266}267268static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {269*R = Integral(A.V ^ B.V);270return false;271}272273static bool neg(Integral A, Integral *R) {274if (Signed && A.isMin())275return true;276277*R = -A;278return false;279}280281static bool comp(Integral A, Integral *R) {282*R = Integral(~A.V);283return false;284}285286template <unsigned RHSBits, bool RHSSign>287static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,288unsigned OpBits, Integral *R) {289*R = Integral::from(A.V << B.V, OpBits);290}291292template <unsigned RHSBits, bool RHSSign>293static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,294unsigned OpBits, Integral *R) {295*R = Integral::from(A.V >> B.V, OpBits);296}297298private:299template <typename T> static bool CheckAddUB(T A, T B, T &R) {300if constexpr (std::is_signed_v<T>) {301return llvm::AddOverflow<T>(A, B, R);302} else {303R = A + B;304return false;305}306}307308template <typename T> static bool CheckSubUB(T A, T B, T &R) {309if constexpr (std::is_signed_v<T>) {310return llvm::SubOverflow<T>(A, B, R);311} else {312R = A - B;313return false;314}315}316317template <typename T> static bool CheckMulUB(T A, T B, T &R) {318if constexpr (std::is_signed_v<T>) {319return llvm::MulOverflow<T>(A, B, R);320} else {321R = A * B;322return false;323}324}325template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {326if constexpr (std::is_signed_v<T>) {327return Min <= V && V <= Max;328} else {329return V >= 0 && static_cast<uint64_t>(V) <= Max;330}331}332};333334template <unsigned Bits, bool Signed>335llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {336I.print(OS);337return OS;338}339340} // namespace interp341} // namespace clang342343#endif344345346