334 lines · c
1//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Defines the VM types and helpers operating on types.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H14#define LLVM_CLANG_AST_INTERP_INTEGRAL_H15 16#include "clang/AST/APValue.h"17#include "clang/AST/ComparisonCategories.h"18#include "llvm/ADT/APSInt.h"19#include "llvm/Support/MathExtras.h"20#include "llvm/Support/raw_ostream.h"21#include <cstddef>22#include <cstdint>23 24#include "Primitives.h"25 26namespace clang {27namespace interp {28 29using APInt = llvm::APInt;30using APSInt = llvm::APSInt;31 32template <bool Signed> class IntegralAP;33 34// Helper structure to select the representation.35template <unsigned Bits, bool Signed> struct Repr;36template <> struct Repr<8, false> {37 using Type = uint8_t;38};39template <> struct Repr<16, false> {40 using Type = uint16_t;41};42template <> struct Repr<32, false> {43 using Type = uint32_t;44};45template <> struct Repr<64, false> {46 using Type = uint64_t;47};48template <> struct Repr<8, true> {49 using Type = int8_t;50};51template <> struct Repr<16, true> {52 using Type = int16_t;53};54template <> struct Repr<32, true> {55 using Type = int32_t;56};57template <> struct Repr<64, true> {58 using Type = int64_t;59};60 61/// Wrapper around numeric types.62///63/// These wrappers are required to shared an interface between APSint and64/// builtin primitive numeral types, while optimising for storage and65/// allowing methods operating on primitive type to compile to fast code.66template <unsigned Bits, bool Signed> class Integral final {67private:68 template <unsigned OtherBits, bool OtherSigned> friend class Integral;69 70 // The primitive representing the integral.71 using ReprT = typename Repr<Bits, Signed>::Type;72 ReprT V;73 static_assert(std::is_trivially_copyable_v<ReprT>);74 75 /// Primitive representing limits.76 static const auto Min = std::numeric_limits<ReprT>::min();77 static const auto Max = std::numeric_limits<ReprT>::max();78 79 /// Construct an integral from anything that is convertible to storage.80 template <typename T> explicit Integral(T V) : V(V) {}81 82public:83 using AsUnsigned = Integral<Bits, false>;84 85 /// Zero-initializes an integral.86 Integral() : V(0) {}87 88 /// Constructs an integral from another integral.89 template <unsigned SrcBits, bool SrcSign>90 explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}91 92 /// Construct an integral from a value based on signedness.93 explicit Integral(const APSInt &V)94 : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}95 96 bool operator<(Integral RHS) const { return V < RHS.V; }97 bool operator>(Integral RHS) const { return V > RHS.V; }98 bool operator<=(Integral RHS) const { return V <= RHS.V; }99 bool operator>=(Integral RHS) const { return V >= RHS.V; }100 bool operator==(Integral RHS) const { return V == RHS.V; }101 bool operator!=(Integral RHS) const { return V != RHS.V; }102 bool operator>=(unsigned RHS) const {103 return static_cast<unsigned>(V) >= RHS;104 }105 106 bool operator>(unsigned RHS) const {107 return V >= 0 && static_cast<unsigned>(V) > RHS;108 }109 110 Integral operator-() const { return Integral(-V); }111 Integral operator-(const Integral &Other) const {112 return Integral(V - Other.V);113 }114 Integral operator~() const { return Integral(~V); }115 116 template <unsigned DstBits, bool DstSign>117 explicit operator Integral<DstBits, DstSign>() const {118 return Integral<DstBits, DstSign>(V);119 }120 121 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>122 explicit operator Ty() const {123 return V;124 }125 126 APSInt toAPSInt() const {127 return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);128 }129 APSInt toAPSInt(unsigned BitWidth) const {130 return APSInt(toAPInt(BitWidth), !Signed);131 }132 APInt toAPInt(unsigned BitWidth) const {133 if constexpr (Signed)134 return APInt(Bits, static_cast<uint64_t>(V), Signed)135 .sextOrTrunc(BitWidth);136 else137 return APInt(Bits, static_cast<uint64_t>(V), Signed)138 .zextOrTrunc(BitWidth);139 }140 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }141 142 Integral<Bits, false> toUnsigned() const {143 return Integral<Bits, false>(*this);144 }145 146 constexpr static unsigned bitWidth() { return Bits; }147 148 bool isZero() const { return !V; }149 150 bool isMin() const { return *this == min(bitWidth()); }151 152 bool isMinusOne() const { return Signed && V == ReprT(-1); }153 154 constexpr static bool isSigned() { return Signed; }155 156 bool isNegative() const { return V < ReprT(0); }157 bool isPositive() const { return !isNegative(); }158 159 ComparisonCategoryResult compare(const Integral &RHS) const {160 return Compare(V, RHS.V);161 }162 163 void bitcastToMemory(std::byte *Dest) const {164 std::memcpy(Dest, &V, sizeof(V));165 }166 167 static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {168 assert(BitWidth == sizeof(ReprT) * 8);169 ReprT V;170 171 std::memcpy(&V, Src, sizeof(ReprT));172 return Integral(V);173 }174 175 std::string toDiagnosticString(const ASTContext &Ctx) const {176 std::string NameStr;177 llvm::raw_string_ostream OS(NameStr);178 OS << V;179 return NameStr;180 }181 182 unsigned countLeadingZeros() const {183 if constexpr (!Signed)184 return llvm::countl_zero<ReprT>(V);185 if (isPositive())186 return llvm::countl_zero<typename AsUnsigned::ReprT>(187 static_cast<typename AsUnsigned::ReprT>(V));188 llvm_unreachable("Don't call countLeadingZeros() on negative values.");189 }190 191 Integral truncate(unsigned TruncBits) const {192 assert(TruncBits >= 1);193 if (TruncBits >= Bits)194 return *this;195 const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;196 const ReprT SignBit = ReprT(1) << (TruncBits - 1);197 const ReprT ExtMask = ~BitMask;198 return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));199 }200 201 void print(llvm::raw_ostream &OS) const { OS << V; }202 203 static Integral min(unsigned NumBits) { return Integral(Min); }204 static Integral max(unsigned NumBits) { return Integral(Max); }205 static Integral zero(unsigned BitWidth = 0) { return from(0); }206 207 template <typename ValT>208 static Integral from(ValT Value, unsigned NumBits = 0) {209 if constexpr (std::is_integral_v<ValT>)210 return Integral(Value);211 else212 return Integral(static_cast<Integral::ReprT>(Value));213 }214 215 template <unsigned SrcBits, bool SrcSign>216 static Integral from(Integral<SrcBits, SrcSign> Value) {217 return Integral(Value.V);218 }219 220 static bool increment(Integral A, Integral *R) {221 return add(A, Integral(ReprT(1)), A.bitWidth(), R);222 }223 224 static bool decrement(Integral A, Integral *R) {225 return sub(A, Integral(ReprT(1)), A.bitWidth(), R);226 }227 228 static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {229 return CheckAddUB(A.V, B.V, R->V);230 }231 232 static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {233 return CheckSubUB(A.V, B.V, R->V);234 }235 236 static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {237 return CheckMulUB(A.V, B.V, R->V);238 }239 240 static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {241 *R = Integral(A.V % B.V);242 return false;243 }244 245 static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {246 *R = Integral(A.V / B.V);247 return false;248 }249 250 static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {251 *R = Integral(A.V & B.V);252 return false;253 }254 255 static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {256 *R = Integral(A.V | B.V);257 return false;258 }259 260 static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {261 *R = Integral(A.V ^ B.V);262 return false;263 }264 265 static bool neg(Integral A, Integral *R) {266 if (Signed && A.isMin())267 return true;268 269 *R = -A;270 return false;271 }272 273 static bool comp(Integral A, Integral *R) {274 *R = Integral(~A.V);275 return false;276 }277 278 template <unsigned RHSBits, bool RHSSign>279 static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,280 unsigned OpBits, Integral *R) {281 *R = Integral::from(A.V << B.V, OpBits);282 }283 284 template <unsigned RHSBits, bool RHSSign>285 static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,286 unsigned OpBits, Integral *R) {287 *R = Integral::from(A.V >> B.V, OpBits);288 }289 290private:291 template <typename T> static bool CheckAddUB(T A, T B, T &R) {292 if constexpr (std::is_signed_v<T>) {293 return llvm::AddOverflow<T>(A, B, R);294 } else {295 R = A + B;296 return false;297 }298 }299 300 template <typename T> static bool CheckSubUB(T A, T B, T &R) {301 if constexpr (std::is_signed_v<T>) {302 return llvm::SubOverflow<T>(A, B, R);303 } else {304 R = A - B;305 return false;306 }307 }308 309 template <typename T> static bool CheckMulUB(T A, T B, T &R) {310 if constexpr (std::is_signed_v<T>) {311 return llvm::MulOverflow<T>(A, B, R);312 } else if constexpr (sizeof(T) < sizeof(int)) {313 // Silly integer promotion rules will convert both A and B to int,314 // even it T is unsigned. Prevent that by manually casting to uint first.315 R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B));316 return false;317 } else {318 R = A * B;319 return false;320 }321 }322};323 324template <unsigned Bits, bool Signed>325llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {326 I.print(OS);327 return OS;328}329 330} // namespace interp331} // namespace clang332 333#endif334