Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/IntegralAP.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_AP_H13#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_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;3031/// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.32/// It will NOT copy the memory (unless, of course, copy() is called) and it33/// won't alllocate anything. The allocation should happen via InterpState or34/// Program.35template <bool Signed> class IntegralAP final {36public:37union {38uint64_t *Memory = nullptr;39uint64_t Val;40};41uint32_t BitWidth = 0;42friend IntegralAP<!Signed>;4344template <typename T, bool InputSigned>45static T truncateCast(const APInt &V) {46constexpr unsigned BitSize = sizeof(T) * 8;47if (BitSize >= V.getBitWidth()) {48APInt Extended;49if constexpr (InputSigned)50Extended = V.sext(BitSize);51else52Extended = V.zext(BitSize);53return std::is_signed_v<T> ? Extended.getSExtValue()54: Extended.getZExtValue();55}5657return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()58: V.trunc(BitSize).getZExtValue();59}6061APInt getValue() const {62if (singleWord())63return APInt(BitWidth, Val, Signed);64unsigned NumWords = llvm::APInt::getNumWords(BitWidth);65return llvm::APInt(BitWidth, NumWords, Memory);66}6768public:69using AsUnsigned = IntegralAP<false>;7071void take(uint64_t *NewMemory) {72assert(!singleWord());73std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));74Memory = NewMemory;75}7677void copy(const APInt &V) {78assert(BitWidth == V.getBitWidth());79assert(numWords() == V.getNumWords());8081if (V.isSingleWord()) {82if constexpr (Signed)83Val = V.getSExtValue();84else85Val = V.getZExtValue();86return;87}88assert(Memory);89std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t));90}9192IntegralAP() = default;93/// Zeroed, single-word IntegralAP of the given bitwidth.94IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) {95assert(singleWord());96}97IntegralAP(uint64_t *Memory, unsigned BitWidth)98: Memory(Memory), BitWidth(BitWidth) {}99IntegralAP(const APInt &V) : BitWidth(V.getBitWidth()) {100if (V.isSingleWord()) {101Val = Signed ? V.getSExtValue() : V.getZExtValue();102} else {103Memory = const_cast<uint64_t *>(V.getRawData());104}105}106107IntegralAP operator-() const { return IntegralAP(-getValue()); }108bool operator>(const IntegralAP &RHS) const {109if constexpr (Signed)110return getValue().sgt(RHS.getValue());111return getValue().ugt(RHS.getValue());112}113bool operator>=(unsigned RHS) const {114if constexpr (Signed)115return getValue().sge(RHS);116return getValue().uge(RHS);117}118bool operator<(IntegralAP RHS) const {119if constexpr (Signed)120return getValue().slt(RHS.getValue());121return getValue().ult(RHS.getValue());122}123124template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>125explicit operator Ty() const {126return truncateCast<Ty, Signed>(getValue());127}128129template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {130if (NumBits == 0)131NumBits = sizeof(T) * 8;132assert(NumBits > 0);133assert(APInt::getNumWords(NumBits) == 1);134APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);135return IntegralAP<Signed>(Copy);136}137138constexpr uint32_t bitWidth() const { return BitWidth; }139constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }140constexpr bool singleWord() const { return numWords() == 1; }141142APSInt toAPSInt(unsigned Bits = 0) const {143if (Bits == 0)144Bits = bitWidth();145146APInt V = getValue();147if constexpr (Signed)148return APSInt(getValue().sext(Bits), !Signed);149else150return APSInt(getValue().zext(Bits), !Signed);151}152APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }153154bool isZero() const { return getValue().isZero(); }155bool isPositive() const {156if constexpr (Signed)157return getValue().isNonNegative();158return true;159}160bool isNegative() const {161if constexpr (Signed)162return !getValue().isNonNegative();163return false;164}165bool isMin() const {166if constexpr (Signed)167return getValue().isMinSignedValue();168return getValue().isMinValue();169}170bool isMax() const {171if constexpr (Signed)172return getValue().isMaxSignedValue();173return getValue().isMaxValue();174}175static constexpr bool isSigned() { return Signed; }176bool isMinusOne() const { return Signed && getValue().isAllOnes(); }177178unsigned countLeadingZeros() const { return getValue().countl_zero(); }179180void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }181std::string toDiagnosticString(const ASTContext &Ctx) const {182std::string NameStr;183llvm::raw_string_ostream OS(NameStr);184print(OS);185return NameStr;186}187188IntegralAP truncate(unsigned BitWidth) const {189if constexpr (Signed)190return IntegralAP(191getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth()));192else193return IntegralAP(194getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth()));195}196197IntegralAP<false> toUnsigned() const {198return IntegralAP<false>(Memory, BitWidth);199}200201void bitcastToMemory(std::byte *Dest) const {202llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);203}204205static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth,206IntegralAP *Result) {207APInt V(BitWidth, static_cast<uint64_t>(0), Signed);208llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);209Result->copy(V);210}211212ComparisonCategoryResult compare(const IntegralAP &RHS) const {213assert(Signed == RHS.isSigned());214assert(bitWidth() == RHS.bitWidth());215APInt V1 = getValue();216APInt V2 = RHS.getValue();217if constexpr (Signed) {218if (V1.slt(V2))219return ComparisonCategoryResult::Less;220if (V1.sgt(V2))221return ComparisonCategoryResult::Greater;222return ComparisonCategoryResult::Equal;223}224225assert(!Signed);226if (V1.ult(V2))227return ComparisonCategoryResult::Less;228if (V1.ugt(V2))229return ComparisonCategoryResult::Greater;230return ComparisonCategoryResult::Equal;231}232233static bool increment(IntegralAP A, IntegralAP *R) {234APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);235return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);236}237238static bool decrement(IntegralAP A, IntegralAP *R) {239APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);240return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);241}242243static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {244return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);245}246247static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {248return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);249}250251static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {252return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);253}254255static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {256if constexpr (Signed)257R->copy(A.getValue().srem(B.getValue()));258else259R->copy(A.getValue().urem(B.getValue()));260return false;261}262263static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {264if constexpr (Signed)265R->copy(A.getValue().sdiv(B.getValue()));266else267R->copy(A.getValue().udiv(B.getValue()));268return false;269}270271static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,272IntegralAP *R) {273R->copy(A.getValue() & B.getValue());274return false;275}276277static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,278IntegralAP *R) {279R->copy(A.getValue() | B.getValue());280return false;281}282283static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,284IntegralAP *R) {285R->copy(A.getValue() ^ B.getValue());286return false;287}288289static bool neg(const IntegralAP &A, IntegralAP *R) {290APInt AI = A.getValue();291AI.negate();292R->copy(AI);293return false;294}295296static bool comp(IntegralAP A, IntegralAP *R) {297R->copy(~A.getValue());298return false;299}300301static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,302IntegralAP *R) {303*R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue()));304}305306static void shiftRight(const IntegralAP A, const IntegralAP B,307unsigned OpBits, IntegralAP *R) {308unsigned ShiftAmount = B.getValue().getZExtValue();309if constexpr (Signed)310R->copy(A.getValue().ashr(ShiftAmount));311else312R->copy(A.getValue().lshr(ShiftAmount));313}314315// === Serialization support ===316size_t bytesToSerialize() const {317assert(BitWidth != 0);318return sizeof(uint32_t) + (numWords() * sizeof(uint64_t));319}320321void serialize(std::byte *Buff) const {322std::memcpy(Buff, &BitWidth, sizeof(uint32_t));323if (singleWord())324std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t));325else {326std::memcpy(Buff + sizeof(uint32_t), Memory,327numWords() * sizeof(uint64_t));328}329}330331static uint32_t deserializeSize(const std::byte *Buff) {332return *reinterpret_cast<const uint32_t *>(Buff);333}334335static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) {336uint32_t BitWidth = Result->BitWidth;337assert(BitWidth != 0);338unsigned NumWords = llvm::APInt::getNumWords(BitWidth);339340if (NumWords == 1)341std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t));342else {343assert(Result->Memory);344std::memcpy(Result->Memory, Buff + sizeof(uint32_t),345NumWords * sizeof(uint64_t));346}347}348349private:350template <template <typename T> class Op>351static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,352unsigned BitWidth, IntegralAP *R) {353if constexpr (!Signed) {354R->copy(Op<APInt>{}(A.getValue(), B.getValue()));355return false;356}357358const APSInt &LHS = A.toAPSInt();359const APSInt &RHS = B.toAPSInt();360APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));361APSInt Result = Value.trunc(LHS.getBitWidth());362R->copy(Result);363364return Result.extend(BitWidth) != Value;365}366};367368template <bool Signed>369inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,370IntegralAP<Signed> I) {371I.print(OS);372return OS;373}374375template <bool Signed>376IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {377return F;378}379380} // namespace interp381} // namespace clang382383#endif384385386